/**
 * 数据交互模块---基于myslq的
 * 负责数据交互，对题库进行增删查改等操作
 * 根据questions.list文件加载所有题目到内存中
 * 对外提供访问数据的接口
 */

#pragma once
#include <iostream>
#include<string>
#include<unordered_map>
#include"../Comm/Detail.hpp"
#include<memory>
#include<cassert>
#include<vector>
#include<fstream>
#include <mysql/mysql.h>

namespace OnlineOJ
{
    namespace ns_Model
    {
        // 题目信息
        struct Question
        {
            std::string number; // 题号
            std::string title;  // 题目标题
            std::string star;   // 难度：简单、中等、困难
            int cpu_limit;      // cpu限制(s)
            int mem_limit;      // 内存限制(KB)
            std::string desc;   // 题目描述
            std::string header; // 预设代码
            std::string tail;   // 测试用例
        };
        using QuestionPtr=std::shared_ptr<Question>;

        const std::string table_name="oj_questions";//数据库中储存数据的表名

        const std::string host="127.0.0.1";
        const std::string user="OJ_Server";
        const std::string password="123456";
        const std::string dbname="OJ";
        const int port=3306;

        //数据交互
        class Model
        {
        public:
            Model()
            {} 

            //sql语句查询数据
            bool QueryMySql(const std::string& sql,std::vector<QuestionPtr>& questions)
            {
                //创建MySql操作句柄
                MYSQL* mysql=mysql_init(nullptr);

                //连接数据库
                if(mysql_real_connect(mysql,host.c_str(),user.c_str(),password.c_str()
                                    ,dbname.c_str(),port,nullptr,0)==NULL)
                {
                    LOG(ERROR,"mysql_real_connect failed:%s\n",mysql_error(mysql));
                    return false;
                }
                LOG(INFO,"数据库连接成功！\n");

                //设置字符集
                if(mysql_set_character_set(mysql,"utf8")!=0)
                {
                    LOG(ERROR,"mysql_set_character_set failed:%s\n",mysql_error(mysql));
                    mysql_close(mysql);
                    return false;
                }
                LOG(INFO,"设置字符集成功！\n");

                //执行sql语句
                int ret=mysql_query(mysql,sql.c_str());
                if(ret!=0)
                {
                    LOG(ERROR,"%s\n",sql.c_str());
                    LOG(ERROR,"mysql_query failed:%s\n",mysql_error(mysql));
                    mysql_close(mysql);
                    return false;
                }
                LOG(INFO,"%s 执行成功！\n",sql.c_str());

                //获取sql语句执行结果
                MYSQL_RES* res=mysql_store_result(mysql);
                if(res==NULL)
                {
                    LOG(DEBUG,"查询结果获取失败\n");
                    return false;
                }
                LOG(INFO,"%s 执行结果获取成功！\n",sql.c_str());

                //解析结果
                int row_num=mysql_num_rows(res);//获取查询结果的行数

                for(int i=0;i<row_num;i++)
                {
                    auto q=std::make_shared<Question>();
                    //LOG(DEBUG,"%p\n",q.get());
                    //获取一行查询出来的信息
                    MYSQL_ROW row=mysql_fetch_row(res);
                    q->number=row[0];
                    q->title=row[1];
                    q->star=row[2];
                    q->desc=row[3];
                    q->header=row[4];
                    q->tail=row[5];
                    q->cpu_limit=std::atoi(row[6]);
                    q->mem_limit=std::atoi(row[7]);

                    questions.push_back(q);
                }

                //释放结果集
                mysql_free_result(res);
                //关闭mysql句柄
                mysql_close(mysql);
                return true;
            }

            //获取所有题目到questions中
            bool GetAllQuestions(std::vector<QuestionPtr>& questions)
            {
                const std::string sql="select * from "+table_name+";";
                return QueryMySql(sql,questions);
            }

            //获取一个题目到question中
            bool GetOneQuestion(const std::string& num,QuestionPtr& question)
            {
                std::string sql="select * from "+table_name;
                sql+=" where number="+num+";";
                bool ret=false;
                std::vector<QuestionPtr> questions;
                if(QueryMySql(sql,questions))
                {
                    if(questions.size()==1)
                    {
                        ret=true;
                        question=questions[0];
                    }
                }
                return ret;
            }
        };
    }
}